package edu.uwm.RobberKnight.View;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.util.LinkedList;

import javax.swing.JPanel;

import edu.uwm.RobberKnight.Controller.RobberKnightsController;
import edu.uwm.RobberKnight.Model.GameState;
import edu.uwm.RobberKnight.Model.Tile;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;

public class BoardView extends JPanel
{

	private static final long serialVersionUID = -2023284659473762091L;
	
	private RobberKnightsController _controller;
	private int _offsetX;
	private int _offsetY;
	private Point _lastClicked;
	private int _validLocAlpha;
	private boolean _validLocAlphaUp;
	private LinkedList<GuiTile> _tiles;
	private Image _add;
	public static int SIZE = GuiTile.TILE_SIZE;
	public static int WEIGHT = 2;
	public static int QUARTER = SIZE / 4;
	
	public BoardView(RobberKnightsController controller)
	{
		addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				_lastClicked = e.getPoint();
			}
			@Override
			public void mouseReleased(MouseEvent e) {
				_lastClicked = null;
			}
			@Override
			public void mouseClicked(MouseEvent e) {

				if (_controller.getSelectedTile() != null) {
					Point coords = screenToBoard(e.getX(), e.getY());
					_controller.placeTile(coords.x, coords.y);
					return;
				}
				if (_controller.isKnightsPlayable()) {
					for (GuiTile gt : _tiles) {
						Point coords = screenToBoard(e.getX(), e.getY());
						if (gt.getTile().getPosition().equals(coords))
							_controller.placeKnight(gt.getTile());
					}
				}
			}
		});
		addMouseMotionListener(new MouseMotionAdapter() {
			@Override
			public void mouseDragged(MouseEvent event) {
				if(_lastClicked != null)
				{
					Point point = event.getPoint();
					int newOffsetX = _offsetX + point.x - _lastClicked.x;
					int newOffsetY = _offsetY + point.y - _lastClicked.y;
					if((newOffsetX > _offsetX &&  newOffsetX <= 100) || 
					(newOffsetX < _offsetX && newOffsetX >= (GuiTile.TILE_SIZE * _controller.getBoardWidth() * -1) + getWidth() - 100))
						_offsetX = newOffsetX;
					if((newOffsetY > _offsetY && newOffsetY <= 100) || 
					(newOffsetY < _offsetY && newOffsetY >= (GuiTile.TILE_SIZE * _controller.getBoardHeight() * -1) + getHeight() - 100))
						_offsetY = newOffsetY;
					_lastClicked = point;
				}
			}
		});	
		_controller = controller;
		_tiles = new LinkedList<GuiTile>();
		_add = Toolkit.getDefaultToolkit().getImage("src/edu/uwm/RobberKnight/icons/add.png");
	}
	
	int count = 0;
	float speed = 100;
	float xPos = 0;
	
	public void updateState(long time) {
		//Make sure our tile collection matches the board.
		updateTiles();
		
		if(_validLocAlphaUp) {
			_validLocAlpha += (time/1000f)*256;
			if(_validLocAlpha > 255) {
				_validLocAlphaUp = false;
				_validLocAlpha = 255;
			}
		} else {
			_validLocAlpha -= (time/1000f)*256;
			if(_validLocAlpha < 0) {
				_validLocAlphaUp = true;
				_validLocAlpha = 0;
			}
		}
	}
	
	/*
	 *  This only adds new tiles, tiles should never be removed from the board.
	 */
	private void updateTiles() {
		for(Tile tile : _controller.getTiles()) {
			boolean contains = false;
			for(GuiTile gt : _tiles) {
				if(gt.getTile() == tile) {
 					contains = true;
 					break;
				}
			}
			if(!contains)
				_tiles.add(new GuiTile(tile));
		}
	}
	
	@Override
	public void paint(Graphics g)
	{
		g.translate(_offsetX, _offsetY);
		
		//Draw the black background.
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, _controller.getBoardWidth() * GuiTile.TILE_SIZE, _controller.getBoardHeight() * GuiTile.TILE_SIZE);
	
		//Draw all the tiles.
		for(GuiTile tile : _tiles)
		{
			Point coords = boardToScreen(tile.getTile().xPosition(), tile.getTile().yPosition());
			tile.setX(coords.x);
			tile.setY(coords.y);
			if(_controller.getState() != GameState.initialTilePlacement) {
				tile.drawTileFace(g,true);
			}
			else 
				tile.drawTileBack(g);		
		}
		// Draw cross hairs denoting valid tile placements.
		Color white = new Color(255, 255, 255, _validLocAlpha);
		if(!_controller.isKnightsPlayable() || _controller.getSelectedTile() != null) {
			for (Point p : _controller.getValidTileLocs()) {
				drawCrosshairs(g, p, white);
			}
		}
		if (_controller.isKnightsPlayable()){
			LinkedList<Tile> validKnightLocs = _controller.getValidKnightMoves();
			Color red = new Color(255, 0, 0, _validLocAlpha);
			for (Tile t : validKnightLocs) {
				Point p = t.getPosition();
				int x = (p.x * SIZE) + SIZE / 2;
				int y = p.y * SIZE + WEIGHT;
				g.drawImage(_add, x, y, 16, 16, null);
				//TODO: Update this when the Issue #1 is fixed.
				drawOutlinedText(g, "+ " + t.getMinKnight(), Color.WHITE, Color.BLACK, x + 20, y + 10);
				drawCrosshairs(g, p, red);
			}
		}

	}
	
	public void drawCrosshairs(Graphics g, Point p, Color color) {
		g.setColor(color);
		// upper left
		g.fillRect(p.x * SIZE + WEIGHT, p.y * SIZE + WEIGHT, WEIGHT,
				QUARTER);
		g.fillRect(p.x * SIZE + WEIGHT, p.y * SIZE + WEIGHT, QUARTER,
				WEIGHT);

		// upper right
		g.fillRect((p.x * SIZE) + SIZE - QUARTER - WEIGHT, p.y * SIZE
				+ WEIGHT, QUARTER, WEIGHT);
		g.fillRect((p.x * SIZE) + SIZE - WEIGHT, p.y * SIZE + WEIGHT,
				WEIGHT, QUARTER);

		// bottom left
		g.fillRect(p.x * SIZE + WEIGHT, (p.y * SIZE) + SIZE - QUARTER
				- WEIGHT, WEIGHT, QUARTER);
		g.fillRect(p.x * SIZE + WEIGHT, (p.y * SIZE) + SIZE - WEIGHT,
				QUARTER, WEIGHT);

		// bottom right
		g.fillRect((p.x * SIZE) + SIZE - QUARTER, (p.y * SIZE) + SIZE
				- WEIGHT, QUARTER, WEIGHT);
		g.fillRect((p.x * SIZE) + SIZE - WEIGHT, (p.y * SIZE) + SIZE
				- QUARTER - WEIGHT, WEIGHT, QUARTER);
	}
	
	private static void drawOutlinedText(Graphics g, String message, Color inside, Color outside, int x, int y) {
		g.setColor(outside);
		g.drawString(message, x - 1, y);
		g.drawString(message, x + 1, y);
		g.drawString(message, x, y - 1);
		g.drawString(message, x, y + 1);
		g.setColor(inside);
		g.drawString(message, x, y);
	}
	
	public Point screenToBoard(int x, int y) {
		return new Point((x - _offsetX) / GuiTile.TILE_SIZE, (y - _offsetY) / GuiTile.TILE_SIZE);
	}
	
	public Point boardToScreen(int x, int y) {
		return new Point(x * GuiTile.TILE_SIZE, y * GuiTile.TILE_SIZE);
	}
	
	public void centerScreen() {
		_offsetX = -(_controller.getBoardWidth() * GuiTile.TILE_SIZE) / 2 + (getWidth() / 2);
		_offsetY = -(_controller.getBoardHeight() * GuiTile.TILE_SIZE) / 2 + (getHeight() / 2);
	}
	
	@Override
	public int getWidth() {
		return super.getWidth();
	}
	
	@Override
	public int getHeight() {
		return super.getHeight();
	}

}
